
package org.fli.lang;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Main
{
   class Node
   {
      Object data;
      Node parent;
      List<Node> children;
      
      public Node(Object data, Node parent)
      {
         this.data = data;
         this.parent = parent;
         children = new ArrayList<Node>();
      }
      
      public Node getParent()
      {
         return parent;
      }
      public void setParent(Node parent)
      {
         this.parent = parent;
      }
      public Object getData()
      {
         return data;
      }
      public List<Node> getChildren()
      {
         return children;
      }
      
      
   }
	
   class SrcNode
   {
      SrcNode parent;
      List<SrcNode> children;
      char [] src;//original src prog
      int start, end; //start and end chars of this node
      
      public SrcNode(SrcNode parent, char [] src, int start, int end)
      {         
         this.src = src;
         this.start = start;
         this.end = end;
         this.parent = parent;
      }
      
      private void addChild(SrcNode node)
      {
         if(children == null)
            children = new ArrayList<SrcNode>();
         
         children.add(node);
      }
    
      public int parse()
      {
         int p = start;
         while(p <= end)
         {  
            //skip any whitepace to get to next token
            if(Character.isWhitespace(src[p]))
            {
               while(Character.isWhitespace(src[p]) && p <= end )
                  p++;
            }
            //if its an '(' then find its matching ')'
            //create a new child of its contained text and parse it 
            else if(src[p] == '(')
            {
               int closing = findClosing(p); 
               if(closing == 0)
                  throw new RuntimeException("Cannot find closing ) for |" + this + "|");
               
               if(closing - p > 1)
               {
                  SrcNode child = new SrcNode(this, src, p + 1, closing - 1);
                  addChild(child);
                  p = child.parse();
               }
               else
                  p++;
            }
            //If its a token then read it until you get to next whitespace or '(' or ')'
            //and make a child of it
            else
            {
               int childStart = p;
               while(!Character.isWhitespace(src[p]) && 
                     src[p]!='(' && src[p]!=')' && p <= end )
               {
                  p++;
               }
               SrcNode child = new SrcNode(this, src, childStart, p - 1);
               addChild(child);
               p++;
               
            }
         }
         
         return p;
         

      }

      public void print(int nTabs)
      {
         if(children == null)
         {
            String tabs = "";
            for(int i = 0; i < nTabs; i++)
               tabs += "\t";
            Main.print(tabs + this.toString());
         }
         else
         {
            nTabs++;
            for (SrcNode child : children)
            {
               child.print(nTabs);
            }
         }
      }

      public int findClosing(int opening)
      {
         int p = opening + 1;
         int openings = 1;
         while(p <= end)
         {
            if(src[p] == '(')
               openings++;
            
            if(src[p] == ')')
            {
               openings--;
               if(openings == 0)
                  return p;
            }
            p++;
         }   
         return 0;
      }

    
      public String toString()
      {
         return new String(src, start, (end - start) + 1);
      }
   }
   
	public static void main(String[] args) throws IOException
	{

	   String filePath = args[0];
	   print("Running " + filePath);
	   File f = new File(filePath);
      BufferedReader in = new BufferedReader(new FileReader(f));
      
      char[] src = new char[(int)f.length()]; 
      in.read(src);
      
      new Main().execute(src);
	}
	

	public void execute(char[] src)
	{
	  SrcNode srcNode = new SrcNode(null, src, 0, src.length - 1);
	  srcNode.parse();
	  srcNode.print(1);
	  int i = 1;
	}
	
	
	public static void print(String s)
	{
	   System.out.println(s);
	}
}